package com.tangyuan.user.service.impl;


import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tangyuan.common.config.RedissonConfig;
import com.tangyuan.common.payment.AliPayImpl;
import com.tangyuan.common.payment.WxPayImpl;
import com.tangyuan.common.result.Result;
import com.tangyuan.common.result.ResultCodeEnum;
import com.tangyuan.common.util.iospay.AppleRequestProtocol;
import com.tangyuan.common.util.iospay.AppleVerifyUtil;
import com.tangyuan.dto.GivingLiveGiftDto;
import com.tangyuan.model.*;
import com.tangyuan.result.oConvertUtils;
import com.tangyuan.user.mapper.UserBalanceMapper;
import com.tangyuan.user.service.ITyFinanceService;
import com.tangyuan.user.service.IUserBalanceService;
import com.tangyuan.user.service.IUserService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @Description: user_balance
 * @Author: jeecg-boot
 * @Date: 2024-03-12
 * @Version: V1.0
 */
@Service
@Transactional
@Slf4j
public class UserBalanceServiceImpl extends ServiceImpl<UserBalanceMapper, UserBalance> implements IUserBalanceService {
    @Autowired
    private WxPayImpl wxPayService;
    @Autowired
    private ITyFinanceService tyFinanceService;
    @Autowired
    private UserBalanceMapper userBalanceMapper;
    @Autowired
    private IUserService userService;

    private final RedissonClient redissonClient = RedissonConfig.createRedissonClient();


    @Override
    public Result<Object> saveUserBalance(Long userId, TyFinance tyFinance) {
        if (userId == null) {
            return Result.build(null, ResultCodeEnum.LOGIN_AUTH);
        }
        if (Objects.isNull(tyFinance) || tyFinance.isEmpty()) {
            return Result.build(null, ResultCodeEnum.ARGUMENT_VALID_ERROR);
        }
        if (tyFinance.getPayWay() != 1 && tyFinance.getPayWay() != 2 && tyFinance.getPayWay() != 4) {
            return Result.build(null, ResultCodeEnum.PAY_WAY_NOT_SUPPORT);
        }
        if (tyFinance.getTotalAmount().compareTo(new BigDecimal(0)) <= 0) {
            return Result.build(null, ResultCodeEnum.INCORRECT_PAYMENT_AMOUNT);
        }
        String orderNo = "RC" + oConvertUtils.orderNo();
        tyFinance.setUserId(userId);
        tyFinance.setOrderNo(orderNo);
        tyFinance.setStatus(1);
        tyFinance.setCreateTime(new Date());
        tyFinance.setUpdateTime(new Date());
        tyFinance.setType(5);

        Orders orders = new Orders();
        orders.setOrderNo(orderNo);
        orders.setPayType(tyFinance.getPayWay());
        orders.setPayBalance(tyFinance.getTotalAmount());
        orders.setShopName("余额充值");
        tyFinanceService.save(tyFinance);
        if (tyFinance.getPayWay() == 1) {
            // 调取微信支付
            return wxPayService.wxPay(orders);
        } else if (tyFinance.getPayWay() == 2) {
            // 调取支付宝支付
            return AliPayImpl.pay(orders);
        } else if (tyFinance.getPayWay() == 4) {
            // IOS内购调用，创建一下订单，返回订单号 后续逻辑票据校验接口处理
            Map<String, String> result = new HashMap<>();
            result.put("orderNo", orders.getOrderNo());
            result.put("productId", tyFinance.getProductId());
            return Result.ok(result);
        }
        return Result.build(null, ResultCodeEnum.PAY_WAY_NOT_SUPPORT);
    }

    @Override
    public Result<Object> cashUserBalance(Long userId, NyqmCustomerTixian params) {
//        String errMsg = "提现失败，请联系管理员";
//        BigDecimal rel = new BigDecimal("0.006");
//
//        try {
//            if (nyqmCustomer.getBalance().compareTo(params.getMoney()) < 0) {
//                return com.tangyuan.vo.Result.error("您的余额不足，请输入正确金额");
//            }
//            String openId = nyqmCustomer.getOpenId();
//            String txNo = "TX" + oConvertUtils.orderNo();
//            String username = nyqmCustomer.getNickName();
////            if (StringUtils.isNotEmpty(params.getCode())) {
////                openId = getOpenId(params.getCode());
////            }
//            NyqmCustomerAli userAli = new NyqmCustomerAli();
//            if (params.getType() == 2) {
//                userAli = userAliMapper.selectOne(new QueryWrapper<NyqmCustomerAli>()
//                        .eq("customer_id", nyqmCustomer.getId())
//                        .eq("is_del", 0)
//                        .eq("is_default", true));
//                if (ObjectUtil.isEmpty(userAli)) {
//                    //自定义错误码419，前端根据这个返回其他操作
//                    return com.tangyuan.vo.Result.error(419, "请先绑定支付宝");
//                }
//                params.setTxName(userAli.getName());
//                params.setTxIdentity(userAli.getIdentity());
//            }
//            params.setTixNo(txNo);
//            params.setCustomerName(username);
//            //是否自动提现
//            if (nyqmBasic.getIsRefund()) {
//                params.setExamine(2);
//                params.setExamineUser("自动提现");
//                if (!this.save(params)) {
//                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
//                    return com.tangyuan.vo.Result.error(errMsg);
//                }
//
//                //给个改变后的后的余额    原余额 - (提现金额 - 提现金额 *0.006)
//                //手续费
//                BigDecimal relMoney = params.getMoney().multiply(rel).setScale(2, RoundingMode.HALF_UP);
//                //减去手续费后的提现金额
//                BigDecimal realMoney = params.getMoney().subtract(relMoney);
//                // 剩余余额
//                BigDecimal subtract = nyqmCustomer.getBalance().subtract(params.getMoney());
//                params.setRel(relMoney);
//                params.setRealMoney(realMoney);
//
//                //放入财务
//                if (!cashFinance(params)) {
//                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
//                    return com.tangyuan.vo.Result.error(errMsg);
//                }
//
//                nyqmCustomer.setBalance(subtract);
//                if (customerMapper.updateById(nyqmCustomer) != 1) {
//                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
//                    return com.tangyuan.vo.Result.error(errMsg);
//                }
//                UserBalance balance = new UserBalance();
//                balance.setUserId(params.getUserId());
//                //提现
//                balance.setType(4);
//                balance.setBalance(params.getMoney());
//                balance.setOrderNo(params.getTixNo());
//                balance.setUpBalance(subtract);
//
//                if (this.baseMapper.insert(balance) != 1) {
//                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
//                    return com.tangyuan.vo.Result.error(errMsg);
//                }
//                //微信提现
//                if (params.getType() == 1) {
//                    WithdrawalParamDto dto = new WithdrawalParamDto();
//                    BigDecimal multiply = params.getRealMoney().multiply(new BigDecimal(100));
//                    dto.setAmount(multiply.intValue());
//                    dto.setReUserName(username);
//                    dto.setOpenId(openId);
//                    dto.setTradeNo(txNo);
//                    String accounts = initiateBatchTransfer.transferAccounts(dto);
//                    Batche batche = JSON.parseObject(accounts, Batche.class);
//                    if (StringUtils.isNotEmpty(batche.getCode())) {
//                        //todo 提现失败具体业务逻辑
//                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
//                        return com.tangyuan.vo.Result.error(batche.getMessage());
//                    } else {
//                        //todo 提现成功具体业务逻辑
//                        return com.tangyuan.vo.Result.ok("提现成功,手续费:" + relMoney);
//                    }
//                } else if (params.getType() == 2) {
//                    //支付宝
//                    AliPayCashOutDto aliPayCashOutDto = new AliPayCashOutDto();
//                    aliPayCashOutDto.setOrderNo(txNo);
//                    aliPayCashOutDto.setIdentity(params.getIdentity());
//                    aliPayCashOutDto.setName(params.getName());
//                    aliPayCashOutDto.setBizScene("DIRECT_TRANSFER");
//                    aliPayCashOutDto.setTransAmount(params.getRealMoney().toString());
//                    aliPayCashOutDto.setOrderTitle("凝颜卿美提现");
//                    com.tangyuan.vo.Result<Object> transfer = NyqmAlipayController.transferAccounts(aliPayCashOutDto);
//                    if (transfer.getCode() != 200) {
//                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
//                        return com.tangyuan.vo.Result.error(errMsg);
//                    }
//                }
//                return com.tangyuan.vo.Result.ok("提现成功,手续费:" + relMoney);
//            } else {
//                params.setExamine(1);
//                params.setTixNo(txNo);
//                params.setCustomerName(params.getName());
//                params.setOpenId(openId);
//                if (!this.save(params)) {
//                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
//                    return com.tangyuan.vo.Result.error(errMsg);
//                }
//                return com.tangyuan.vo.Result.ok("提现申请成功！");
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//        return com.tangyuan.vo.Result.error(errMsg);
        return null;
    }

    @Override
    public Result<Object> iosRechargeVerify(AppleRequestProtocol request) {
        // 票据
        String receipt = request.getReceipt();
        // 服务端自己的订单号，可用做后续业务逻辑
        String orderId = request.getOrderNumber();
        // 注意，有的票据在客户端接收时 加号 可能会被转换为 空格
        String data = receipt.replace(" ", "+");
        // 请求苹果服务器进行票据验证
        String result = AppleVerifyUtil.verifyApple(data, 1);
        JSONObject receiptData = JSONObject.parseObject(result);
        // 解析票据
        if (result == null) {
            // 解析票据失败 或 网络问题
            log.error("[解析票据失败，result为空]");
        } else {
            // 支付环境是否正确
            int status = receiptData.getInteger("status");
            if (21007 == status) {
                // 验证失败21007 走沙箱环境
                result = AppleVerifyUtil.verifyApple(data, 0);
                log.debug("【票据校验结果===】" + result);
                if (result == null) {
                    //  解析票据失败
                    log.error("[解析票据失败，result为空]");
                    return Result.build(null, ResultCodeEnum.RECEIPT_VERIFY_ERROR);
                }
                receiptData = JSONObject.parseObject(result);
                status = receiptData.getInteger("status");
            }

            if (0 == status) {
                JSONObject receiptInfo = receiptData.getJSONObject("receipt");
                JSONArray inAppList = receiptInfo.getJSONArray("in_app");
                if (!CollectionUtils.isEmpty(inAppList)) {
                    JSONObject inApp = inAppList.getJSONObject(inAppList.size() - 1);
                    // 票据ID
                    String transactionId = inApp.getString("transaction_id");
                    // 购买时间
                    Long purchaseDateMs = inApp.getLong("purchase_date_ms");
                    // 商品ID 与在APP Store 后台配置的一致
                    // String productId = inApp.getString("product_id");

                    // 剩余业务逻辑
                    QueryWrapper<TyFinance> wrapper = new QueryWrapper();
                    wrapper.eq("order_no", orderId);
                    wrapper.eq("status", 1);
                    wrapper.eq("type", 5);
                    TyFinance one = tyFinanceService.getOne(wrapper);
                    if (one != null) {
                        one.setStatus(2);
                        one.setPayWay(4);
                        one.setPayTime(new Date(purchaseDateMs));
                        one.setTransactionId(transactionId);
                        one.setType(5);
                        tyFinanceService.updateById(one);

                        // 旧资金流 2024/5/8 下午3:49 By Wesin
                        UserBalance oldUserBalance = userBalanceMapper.selectByUserId(one.getUserId());

                        // 封装新资金流 2024/5/8 下午3:51 By Wesin
                        UserBalance userBalance = new UserBalance();
                        userBalance.setUserId(one.getUserId());
                        userBalance.setCreateTime(new Date());
                        userBalance.setOrderNo(one.getOrderNo());
                        userBalance.setTransactionId(transactionId);
                        userBalance.setIsDelete(0);
                        userBalance.setBalance(oldUserBalance.getBalance().add(one.getTotalAmount()));
                        userBalance.setStatus(0);
                        userBalance.setType(1);
                        userBalance.setUpBalance(one.getTotalAmount());
                        userBalanceMapper.insert(userBalance);

                        return Result.ok();
                    } else {
                        return Result.build(null, ResultCodeEnum.ORDER_NOT_EXIST);
                    }
                } else {
                    // 获取in_app支付列表失败
                    log.error("[获取in_app支付列表失败]");
                }
            }
        }
        return Result.build(null, ResultCodeEnum.RECEIPT_VERIFY_ERROR);
    }

    @Override
    public UserBalance getUserBalance(Long userId) {
        LambdaQueryWrapper<UserBalance> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserBalance::getUserId, userId);
        queryWrapper.orderByDesc(UserBalance::getCreateTime);
        queryWrapper.last("limit 1");
        return userBalanceMapper.selectOne(queryWrapper);
    }

    public Result<ResultCodeEnum> verifyParameter(GivingLiveGiftDto givingLiveGiftDto){
        if (givingLiveGiftDto == null || givingLiveGiftDto.getUserId() == null || givingLiveGiftDto.getRecipient() == null) {
            return Result.build(null, ResultCodeEnum.ARGUMENT_VALID_ERROR);
        }
        if (givingLiveGiftDto.getUpBalance() == null || givingLiveGiftDto.getUpBalance().compareTo(BigDecimal.ZERO) < 0) {
            return Result.build(null, ResultCodeEnum.INCORRECT_PAYMENT_AMOUNT);
        }
        User user = userService.getUserById(givingLiveGiftDto.getUserId());
        if (user == null) {
            return Result.build(null, ResultCodeEnum.ACCOUNT_ERROR);
        }
        User recipientUser = userService.getUserById(givingLiveGiftDto.getRecipient());
        if (recipientUser == null) {
            return Result.build(null, ResultCodeEnum.ACCOUNT_ERROR);
        }
        UserBalance userBalance = this.getUserBalance(givingLiveGiftDto.getUserId());
        if (userBalance == null || userBalance.getBalance().compareTo(givingLiveGiftDto.getUpBalance()) < 0) {
            return Result.build(null, ResultCodeEnum.ACCOUNT_LESS);
        }
        return Result.ok();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Map<String, UserBalance>> giveLiveGiftUpdateBalance(GivingLiveGiftDto givingLiveGiftDto) {
        RLock lock = redissonClient.getLock("orderNo:" + givingLiveGiftDto.getOrderNo());
        lock.lock(10, TimeUnit.SECONDS);
        try {
            Result<ResultCodeEnum> enumResult = verifyParameter(givingLiveGiftDto);
            if (!enumResult.isOk()) {
                return Result.build(null, enumResult.getCode(), enumResult.getMessage());
            }
            UserBalance userBalance = this.getUserBalance(givingLiveGiftDto.getUserId());
            userBalance.setId(null);
            userBalance.setUserId(givingLiveGiftDto.getUserId());
            userBalance.setType(2);
            userBalance.setTransactionId(givingLiveGiftDto.getOrderNo());
            userBalance.setOrderNo(givingLiveGiftDto.getOrderNo());
            userBalance.setUpBalance(givingLiveGiftDto.getUpBalance());
            userBalance.setBalance(userBalance.getBalance().subtract(givingLiveGiftDto.getUpBalance()));
            userBalance.setCreateTime(new Date());
            userBalance.setUpdateTime(new Date());
            userBalanceMapper.insert(userBalance);

            UserBalance recipientUserBalance = this.getUserBalance(givingLiveGiftDto.getRecipient());
            if (recipientUserBalance == null || recipientUserBalance.isEmpty()) {
                recipientUserBalance = new UserBalance();
                recipientUserBalance.setUserId(givingLiveGiftDto.getRecipient());
                recipientUserBalance.setType(1);
                recipientUserBalance.setTransactionId(givingLiveGiftDto.getOrderNo());
                recipientUserBalance.setOrderNo(givingLiveGiftDto.getOrderNo());
                recipientUserBalance.setUpBalance(givingLiveGiftDto.getUpBalance());
                recipientUserBalance.setBalance(givingLiveGiftDto.getUpBalance());
            } else {
                recipientUserBalance.setId(null);
                recipientUserBalance.setUserId(givingLiveGiftDto.getRecipient());
                recipientUserBalance.setType(1);
                recipientUserBalance.setTransactionId(givingLiveGiftDto.getOrderNo());
                recipientUserBalance.setOrderNo(givingLiveGiftDto.getOrderNo());
                recipientUserBalance.setUpBalance(givingLiveGiftDto.getUpBalance());
                recipientUserBalance.setBalance(recipientUserBalance.getBalance().add(givingLiveGiftDto.getUpBalance()));
            }
            recipientUserBalance.setCreateTime(new Date());
            recipientUserBalance.setUpdateTime(new Date());
            userBalanceMapper.insert(recipientUserBalance);
            Map<String, UserBalance> map = new HashMap<>();
            map.put("giver", userBalance);
            map.put("recipient", recipientUserBalance);
            return Result.ok(map);
        } catch (Exception e) {
            log.error("用户赠送礼物扣款失败,userId:{},orderNo:{}", givingLiveGiftDto.getUserId(), givingLiveGiftDto.getOrderNo(), e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return Result.build(null, ResultCodeEnum.ACCOUNT_SUB_ERROR);
        } finally {
            lock.unlock();
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<ResultCodeEnum> refundLiveGiftUpdateBalance(GivingLiveGiftDto givingLiveGiftDto) {
        RLock lock = redissonClient.getLock("orderNo:" + "RF" + givingLiveGiftDto.getOrderNo());
        lock.lock(10, TimeUnit.SECONDS);
        try {
            UserBalance userBalance = this.getUserBalance(givingLiveGiftDto.getUserId());
            userBalance.setId(null);
            userBalance.setUserId(givingLiveGiftDto.getUserId());
            userBalance.setType(3);
            userBalance.setTransactionId("RF" + givingLiveGiftDto.getOrderNo());
            userBalance.setOrderNo("RF" + givingLiveGiftDto.getOrderNo());
            userBalance.setUpBalance(givingLiveGiftDto.getUpBalance());
            userBalance.setBalance(userBalance.getBalance().add(givingLiveGiftDto.getUpBalance()));
            userBalance.setCreateTime(new Date());
            userBalance.setUpdateTime(new Date());
            userBalanceMapper.insert(userBalance);

            UserBalance recipientUserBalance = this.getUserBalance(givingLiveGiftDto.getRecipient());
            if (recipientUserBalance == null || recipientUserBalance.getBalance().compareTo(givingLiveGiftDto.getUpBalance()) < 0) {
                return Result.build(null, ResultCodeEnum.ACCOUNT_LESS);
            }
            recipientUserBalance.setId(null);
            recipientUserBalance.setUserId(givingLiveGiftDto.getRecipient());
            recipientUserBalance.setType(3);
            recipientUserBalance.setTransactionId("RF" + givingLiveGiftDto.getOrderNo());
            recipientUserBalance.setOrderNo("RF" + givingLiveGiftDto.getOrderNo());
            recipientUserBalance.setUpBalance(givingLiveGiftDto.getUpBalance());
            recipientUserBalance.setBalance(recipientUserBalance.getBalance().subtract(givingLiveGiftDto.getUpBalance()));
            recipientUserBalance.setCreateTime(new Date());
            recipientUserBalance.setUpdateTime(new Date());
            userBalanceMapper.insert(recipientUserBalance);
            return Result.ok();
        } catch (Exception e) {
            log.error("用户赠送礼物退款失败,userId:{},orderNo:{}", givingLiveGiftDto.getUserId(), givingLiveGiftDto.getOrderNo(), e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return Result.build(null, ResultCodeEnum.REFUND_FAILED);
        } finally {
            lock.unlock();
        }
    }
}
